/* eslint-disable no-unused-vars */
/*
 * @Author: bobo
 * @Date: 2021-01-11 13:50:50
 * websocket客户端
 */
export default class WsClient {
  /**
   * @param {String} connectionUrl 连接地址
   * @param {Object} opts 配置参数对象 {
   * autoReconnection: 自动重连，默认false
   * minReconnectionDelay: 最小重连周期，默认1秒
   * maxReconnectionDelay: 最大重连周期，默认2分钟
   * reconnectionStep:重连步长，默认2秒
   * }
   */
  constructor(url, opts = {}) {
    if (url.startsWith('//')) {
      const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws'
      url = `${scheme}:${url}`
    }
    //连接地址
    this.connectionUrl = url
    //是否自动重连,默认false
    this.autoReconnection = opts.autoReconnection || false;
    //最小重连周期，默认1秒
    this.minReconnectionDelay = opts.minReconnectionDelay || 1000
    //最大重连周期，默认2分钟
    this.maxReconnectionDelay = opts.maxReconnectionDelay || 120 * 1000
    //重连步长，默认2秒
    this.reconnectionStep = opts.reconnectionStep || 2000
    //重连定时器id
    this.reconnectTimeoutId = 0
    //重连次数
    this.reconnectionCount = 0
    //手动关闭标识，默认false
    this.manualCloseFlag = false;
    //是否正在重连
    this.isReconning = false;
  }

  _reset() {
    this.reconnectionCount = 0;
    this.isReconning = false;
    clearTimeout(this.reconnectTimeoutId)
  }

  connect(callback = {
    onOpen: undefined,
    onMessage: undefined,
    onReconning: undefined,
    onClosed: undefined,
    onFaile: undefined,
    onManualClose: undefined
  }) {
    //初始化websocket 
    const socket = new WebSocket(this.connectionUrl);
    this.callback = callback;
    socket.addEventListener("open", (event) => {
      this._reset();
      if (this.callback.onOpen) {
        this.callback.onOpen(this.socket.readyState == 1)
      }
    })
    socket.addEventListener('message', (event) => {
      if (this.callback.onMessage) {
        this.callback.onMessage(event.data)
      }
    })
    socket.addEventListener('close', (event) => {
      this.reconnect();
      if (this.callback.onClosed) {
        this.callback.onClosed(event.code, event.reason);
      }
    })
    socket.addEventListener('error', (event) => {
      this.reconnect();
      if (this.callback.onFaile) {
        this.callback.onFaile(-1, 'socket连接出现异常');
      }
    })
    this.socket = socket;
  }

  reconnect() {
    if (!this.autoReconnection || this.manualCloseFlag || this.isReconning) {
      return;
    }
    if (this.socket.readyState == 1 || this.socket.readyState == 0) {
      return;
    }
    this.isReconning = true;
    clearTimeout(this.reconnectTimeoutId)
    this.reconnectionCount++
    let nextDelay = this.minReconnectionDelay + this.reconnectionStep * this.reconnectionCount;
    nextDelay = nextDelay > this.maxReconnectionDelay ? this.maxReconnectionDelay : nextDelay;
    this.reconnectTimeoutId = setTimeout(() => {
      if (this.callback.onReconning) {
        this.callback.onReconning(this.reconnectionCount, nextDelay)
      }
      this.connect(this.callback)
      this.isReconning = false;
    }, nextDelay)
  }

  close() {
    this.manualCloseFlag = true;
    if (this.socket) {
      this.socket.close(4000, '手动关闭WS客户端');
      if (this.callback.onManualClose)
        this.callback.onManualClose()
    } else {
      console.log("websocket 实例不存在，调用失败")
    }
  }
  /**
   * 0 (WebSocket.CONNECTING)
   * 正在链接中
   *1 (WebSocket.OPEN)
   *已经链接并且可以通讯
   *2 (WebSocket.CLOSING)
   *连接正在关闭
   *3 (WebSocket.CLOSED)
   *连接已关闭或者没有链接成功
   */
  state() {
    if (this.socket) {
      return this.socket.readyState;
    } else {
      return -1;
    }
  }

  sendMessage(data) {
    if (this.socket == undefined || data == undefined || data == null) {
      return
    }
    this.socket.send(data)
  }
}